import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.ServerSocket;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

/**
 * Classe qui gere l'interface graphique du damier
 * ainsi que la communication avec les agents
 * @author anane & morchid & laaqoud
 *	Version 1.0
 */

@SuppressWarnings("serial")
public class Damier extends JFrame implements Runnable{


	private static int tailleDamier = 4 ;
	private MulticastSocket ms;
	private ServerSocket s;
	private InetAddress gr;
	private Container c;
	private JTextField taille;
	private JButton boutonModifier;
	private JPanel etat,damier,lignesD,lignesG,boutons;
	private Color Noir = Color.BLACK;
	private Color Blanc = Color.WHITE;
	public int[][] PositionDames;
	public Historique hist;
	
	public Damier(String titre,int w,int h) throws IOException {
		super(titre);
		PositionDames = new int[Damier.getTailledamier()][Damier.getTailledamier()];
		initialize();
		this.setBounds(0, 0, w, h);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setVisible(true);
		
		ms = new MulticastSocket(3000);
		s = new ServerSocket(5000);
		gr = InetAddress.getByName("224.0.0.1");
		hist = new Historique();
	}

	/**
	 * Initialise la fenetre
	 * @throws IOException
	 */
	public void initialize() throws IOException {

		c = this.getContentPane();

		etat = this.CreePanelNorth(tailleDamier);
		c.add(etat, "North");

		damier = this.CreePanelCenter(tailleDamier);
		c.add(damier, "Center");

		lignesG = this.CreePanelNumero(tailleDamier);
		c.add(lignesG, "West");

		lignesD = this.CreePanelNumero(tailleDamier);
		c.add(lignesD, "East");

		boutons = this.CreePanelSouth(tailleDamier);
		c.add(boutons, "South");
	}
	
	/**
	 * Construit une case sur laquelle se trouve une reine
	 * @param couleur
	 * @param valeur
	 * @return une case contenant la dame dont le numero est valeur
	 */
	public Component CasesR(Color couleur, int valeur) {
		Cases c = new Cases(couleur, true, valeur);
		return c;
	}
	
	/**
	 * Construit une case vide
	 * @param couleur
	 * @param valeur
	 * @return une case vide
	 */
	public Component CasesV(Color couleur, int valeur) {
		Cases c = new Cases(couleur, false,valeur);
		return c;
	}
	
	/**
	 * Modifie la taille du damier 
	 * @param i
	 */
	public void setTailledamier(int i) {
		tailleDamier = i;
	}
	
	/**
	 * Taille du damier
	 * @return la taille du damier
	 */
	public static int getTailledamier() {
		return tailleDamier;
	}
	
	/**
	 * Recharge le damier
	 * Lance le Thread (methode run()) qui recharge le damier
	 */
	private void reloadDamier() {
		new Thread(this).start();
	}
	
	/**
	 * Teste si on a trouve une solution
	 * @return true si le jeu est fini, false sinon 
	 */
	public boolean finJeu() {
		int taille = PositionDames.length;
		for (int i = 0; i < taille; i++) {
			for (int j = 0; j < taille; j++) {
				if (PositionDames[i][j]!=0)
					if(pasMenacee(PositionDames[i][j],i,j)){
						continue;
					}
					else
						return false;
			}
		}

		return true;
	}
	
	/**
	 * Teste si la reine n'est pas menacee
	 * @param rang
	 * @param x la ligne sur laquelle se trouve la reine
	 * @param y la colonne sur laquelle se trouve la reine
	 * @return true si la reine n'est pas menacee, false sinon 
	 */
	public boolean pasMenacee(int rang,int x,int y) {
			int taille = PositionDames.length;
			for (int i = 0; i < taille; i++) {
				for (int j = 0; j < taille; j++) {
					if((x == i || y == j || Math.abs(x - i) == Math.abs(y-j)) && PositionDames[i][j]!=rang && PositionDames[i][j]!=0){
						return false;
					}
				}
			}
			return true;	
	}
	
	/**
	 * Cree un panel contenant un bouton pour modifier la taille du damier
	 * @param t
	 * @return
	 */
	public JPanel CreePanelNorth(int t) {
		
		GridLayout layout = new GridLayout(2, 1);
		JPanel PanNorth = new JPanel(layout);
		
		
		JPanel PanEtat = new JPanel();
		taille = new JTextField(Integer.toString(tailleDamier));
		taille.setPreferredSize(new Dimension(35, 25));
		boutonModifier = new JButton("Modifier la taille");
		boutonModifier.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent a) {
				int i = 0;
				try{
					i = Integer.parseInt(taille.getText());
				}
				catch(NumberFormatException nfe){
					i = 4;
				}
				if(i<=3 || i>=100)
					JOptionPane.showMessageDialog(null, "Veuillez indiquer une dimension comprise entre 4 et 100", "ALERTE", JOptionPane.ERROR_MESSAGE);
				else{
					Damier.this.setTailledamier(i);
					PositionDames = new int[Damier.getTailledamier()][Damier.getTailledamier()];
					c.remove(damier);
					c.remove(etat);
					c.remove(lignesG);
					c.remove(lignesD);
					c.remove(boutons);

					damier = CreePanelCenter(i);
					etat = CreePanelNorth(i);
					lignesG = CreePanelNumero(i);
					lignesD = CreePanelNumero(i);
					boutons = CreePanelSouth(i);
					
					c.add(etat, "North");
					c.add(lignesG, "West");
					c.add(lignesD, "East");
					c.add(damier, "Center");
					c.add(boutons, "South");

					c.validate();
				}
			}
		});
		PanEtat.add(taille);
		PanEtat.add(boutonModifier);

		GridLayout layout1 = new GridLayout(1,t);
		JPanel PanColones = new JPanel(layout1);	
		PanColones.setBackground(Color.black);
		
		for(int i = 1; i<t+1; i++) {
			JLabel num = new JLabel(""+i,SwingConstants.CENTER);
			num.setFont(new Font("sansserif", Font.BOLD, 17));
			num.setForeground(Color.WHITE);
			PanColones.add(num);
		}	

		PanNorth.add(PanEtat);
		PanNorth.add(PanColones);

		return PanNorth;
	}
	
	/**
	 * Cree un panel contenant les numeros des lignes
	 * @param t taille du damier
	 * @return
	 */
	public JPanel CreePanelNumero(int t) {
		GridLayout layout = new GridLayout(t, 0);
		JPanel PanLignes = new JPanel(layout);
		PanLignes.setBackground(Color.black);

		for(int i=1; i<t+1; i++) {
			JLabel num  = new JLabel(""+i,SwingConstants.CENTER);			
			num.setFont(new Font("sansserif", Font.BOLD, 17));
			num.setForeground(Color.WHITE);
			num.setPreferredSize(new Dimension(25,0));
			PanLignes.add(num);
		}
		return PanLignes;
	}
	
	/**
	 * Cree un panel contenant le plateau du damier
	 * @param t
	 * @return
	 */
	public JPanel CreePanelCenter(int t) {
		GridLayout layout = new GridLayout(t,t);
		JPanel PanDamier = new JPanel(layout);	
		
		PanDamier.setBackground(Color.black);

		for(int i=0; i<t; i++) {
			for(int j=0; j<t; j++) {
				if(PositionDames[i][j]!=0){
					if((i % 2 == 0 && j % 2 == 0) || (i % 2 !=0 && j % 2 != 0))
						PanDamier.add(this.CasesR(Noir,PositionDames[i][j]));
					else
						PanDamier.add(this.CasesR(Blanc,PositionDames[i][j]));
				}
				else{
					if((i % 2 == 0 && j % 2 == 0) || (i % 2 !=0 && j % 2 != 0))
						PanDamier.add(this.CasesV(Noir,0));
					else
						PanDamier.add(this.CasesV(Blanc,0));
				}
			}
		}
		return PanDamier;
	}
	
	/**
	 * Cree un panel contenant les bouton du lancement du jeu
	 * @param t
	 * @return
	 */
	public JPanel CreePanelSouth(int t){
		GridLayout layout = new GridLayout(2,1);
		JPanel PanSouth = new JPanel(layout);
		

		GridLayout layout1 = new GridLayout(1,t);
		JPanel PanColonnes = new JPanel(layout1);
		PanColonnes.setBackground(Color.black);

		for(int i = 1; i<t+1; i++){
			JLabel num = new JLabel(""+i,SwingConstants.CENTER);
			num.setFont(new Font("sansserif", Font.BOLD, 17));
			num.setForeground(Color.WHITE);
			PanColonnes.add(num);
		}	

		JPanel PanBoutons = new JPanel();
	
		JButton boutonInit = new JButton("Init");
		boutonInit.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent a) {
				int taille = Damier.getTailledamier();
				for(int i=0; i<taille; i++){
					for(int j=0; j<taille; j++){
						if(i == j){
							PositionDames[i][j] = i+1;
						}
						else
							PositionDames[i][j] = 0;
					}
				}
				reloadDamier();
				hist.empiler(PositionDames);
			}
		});
		
		JButton boutonStart = new JButton("Jouer");
		boutonStart.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent a) {
				byte[] buffer = new byte[1024];
				boolean fini = false;
				int nbEchanges = 0;
				try {
					buffer ="1".getBytes();
					DatagramPacket p = new DatagramPacket(buffer,buffer.length,gr,3000);
					ms.send(p);
					while (fini==false){
						ConnexionAgent agent = new ConnexionAgent(s.accept(),PositionDames);	
						agent.start();
						agent.join();
						nbEchanges++;
						hist.empiler(PositionDames);
						fini = finJeu();
					}	
					buffer = "STOP".getBytes();
					p = new DatagramPacket(buffer,buffer.length,gr,3000);
					ms.send(p);
					reloadDamier();
					ImageIcon img = new ImageIcon("firework.gif");
					JOptionPane.showMessageDialog(null,"Felicitation", "Resultat trouve", JOptionPane.INFORMATION_MESSAGE, img);
					
					System.out.println("Nombre de communication : "+nbEchanges);
					

				} catch (IOException e) {
					e.printStackTrace();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
		});
		
		JButton boutonReplay = new JButton("Replay");
		boutonReplay.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent a) {
				if(!hist.estVide()){
					PositionDames = new int[tailleDamier][tailleDamier];
					PositionDames = hist.depiler();
					reloadDamier();
					hist.vider();
				}
			}
			
		});
		
		
		
		JButton boutonStop = new JButton("Stop");
		boutonStop.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent a) {
				byte[] buffer = new byte[1024];
				try {
					buffer = "STOP".getBytes();
					DatagramPacket p = new DatagramPacket(buffer,buffer.length,gr,3000);
					ms.send(p);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		});
		

		
		JButton boutonReset = new JButton("Reset");
		boutonReset.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent a) {
				System.out.println("----------------RESET--------------");
				byte[] buffer = new byte[1024];
				try {
					buffer = "RA".getBytes();
					DatagramPacket p = new DatagramPacket(buffer,buffer.length,gr,3000);
					ms.send(p);
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				hist = new Historique();
				int taille = Damier.getTailledamier();
				PositionDames = new int[taille][taille];
				reloadDamier();
			}
		});
		
		
		PanBoutons.add(boutonInit);
		PanBoutons.add(boutonStart);
		PanBoutons.add(boutonReplay);
		PanBoutons.add(boutonStop);
		PanBoutons.add(boutonReset);
		
		PanSouth.add(PanColonnes);
		PanSouth.add(PanBoutons);

		return PanSouth;
	}
	
	public void run() {
		c.remove(damier);
		damier = CreePanelCenter(getTailledamier());		
		c.add(damier, "Center");
		c.validate();
		
	}
	
	public static void main(String[] args) throws IOException {
		Damier maFenetre = new Damier("Jeu de la Reine", 750, 800);
		maFenetre.setLocationRelativeTo(maFenetre.getParent());
	}
	
	

}
